﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Krist_em_up.Plateforms;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using Microsoft.Xna.Framework.Storage;
using System.Xml.Serialization;

namespace Krist_em_up.Level
{
    [Serializable]
    public class Map
    {
        protected Plateform[,] _map;
        [NonSerialized]
        protected Texture2D background, plateform;

        protected SerializableTexture s_plateforms, s_background;
        public Texture2D Plateform
        {
            get
            {
                return plateform;
            }
            set
            {
                plateform = value;
            }
        }
        public LinkedList<Vector2> ennemiesSpawnPositions;
        
        protected Vector2 spawnPosition;

        public Vector2 endOfLevel { get; set; }

        public Vector2 Spawn
        {
            get
            {
                return spawnPosition;
            }
            set
            {
                if (IsInBounds<Plateform>(_map, (int)value.X, (int)value.Y))
                    spawnPosition = value;
            }
        }

        public Map(Plateform[,] plateforms, Vector2 spawn, Vector2 end)
        {
            _map = plateforms;
            spawnPosition = spawn;
            endOfLevel = end;
        }

        public Map()
        {
            _map = new Plateform[50, 30];
            for (int x = 0; x < _map.GetLength(0); x++)
            {
                for (int y = 0; y < _map.GetLength(1); y++)
                {
                    _map[x, y] = new Plateform(null, TileCollision.Passable);
                }
            }

            ennemiesSpawnPositions = new LinkedList<Vector2>();
        }

        public Vector2 GetSpanPosition()
        {
            if (spawnPosition == null)
            {
                throw new Exception("No span point");
            }
            else
                return spawnPosition;
        }

        public Vector2 GetEndPosition()
        {
            if (endOfLevel == null)
            {
                throw new Exception("No span point");
            }
            else
                return endOfLevel;
        }

        public int GetLength(uint i)
        {
            return _map.GetLength((int)i);
        }

        public Plateform[,] Plateforms
        {
            get { return _map; }
        }

        #region I/O
        public void SaveToFile(string path)
        {
            try
            {
                s_plateforms = new SerializableTexture(plateform);
                s_background = new SerializableTexture(background);
                FileStream f = new FileStream(path, FileMode.OpenOrCreate, FileAccess.Write);
                BinaryFormatter formatter = new BinaryFormatter();
                
                formatter.Serialize(f, this);
                f.Close();
            }
            catch (Exception e)
            {
                e.GetType();
            }
        }
        public static Map LoadFromFile(string path, GraphicsDevice g)
        {
            try
            {
                if (File.Exists(path))
                {
                    FileStream stream = File.Open(path, FileMode.Open, FileAccess.ReadWrite);
                    BinaryFormatter bf = new BinaryFormatter();

                    Map m = (Map)bf.Deserialize(stream);
                    m.LoadTextures(g);
                    stream.Close();
                    return m;
                }

            }
            catch (Exception e) { e.GetType(); }
            return null;
        }
        #endregion

        protected void LoadTextures(GraphicsDevice g)
        {
            plateform = s_plateforms.ToTexture2D(g);
            background = s_background.ToTexture2D(g);
        }
        public void AddPlateform(Vector2 coords)
        {
            if (IsInBounds<Plateform>(_map, (int)coords.X, (int)coords.Y))
                Plateforms[(int)coords.X, (int)coords.Y] = new Plateform(Plateform, TileCollision.Impassable);
        }

        public void RemovePlateform(Vector2 coords)
        {
            if (IsInBounds<Plateform>(_map, (int)coords.X, (int)coords.Y))
                Plateforms[(int)coords.X, (int)coords.Y] = new Plateform(null, TileCollision.Passable);
        }

        public static bool IsInBounds<T>(T[,] array, int x, int y)
        {
            return (x >= 0 && y >= 0 && x < array.GetLength(0) && y < array.GetLength(1));
        }
    }

    [Serializable]
    public class SerializableTexture
    {
        protected int height, width;

        protected Color[] c;

        public SerializableTexture(Texture2D t)
        {
            if (t == null)
                return;
            else
            {
                height = t.Height;
                width = t.Width;
                c = new Color[height * width];
                t.GetData<Color>(c);
            }
        }

        public Texture2D ToTexture2D(GraphicsDevice graphics)
        {
            if (width == 0 && height == 0)
                return null;
            Texture2D t = new Texture2D(graphics, width, height);
            t.SetData<Color>(c);
            return t;
        }
    }
}
